package client.http;

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;

import org.apache.commons.lang.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;

import core.AlertUtil;
import core.TextAreaAppender;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;

public class HttpClientController implements Initializable{

	private static final String LINE_SEPARATOR = System.getProperty("line.separator");

	//应用日志对象
	private Logger appLogger;

	/**
	 * 日志组件
	 */
	@FXML
	private TextArea logTextArea;

	@FXML
	private ChoiceBox<String> methodChoiceBox;

	@FXML
	private TextField urlTextField;

	@FXML
	private TextArea requestBodyTextArea;

	@FXML
	private TextArea requestHeadTextArea;

	@FXML
	private TextArea responseBodyTextArea;

	@FXML
	private TextArea responseHeadTextArea;

	@FXML
	private TextField connectTimeoutTextField;

	@FXML
	private TextField connectionRequestTimeoutTextField;

	@FXML
	private TextField socketTimeoutTextField;

	@FXML
	private TextField redirectsEnabledTextField;

	@FXML
	private TextField relativeRedirectsAllowedTextField;

	@FXML
	private TextField circularRedirectsAllowedTextField;

	@FXML
	private TextField maxRedirectsTextField;

	@FXML
	private TextField defaultRequestEncodingTextField;

	@FXML
	private TextField defaultResponseEncodingTextField;

	@Override
	public void initialize(URL location, ResourceBundle resources) {
		appLogger = Logger.getLogger("http_client_app");
		appLogger.addAppender(new TextAreaAppender(logTextArea));
		appLogger.info("日志输出初始化完成！");

		urlTextField.setOnAction((value)->{
			sendRequest();
		});

		//default headers
		requestHeadTextArea.appendText("Connection: close"+LINE_SEPARATOR);
		requestHeadTextArea.appendText("User-Agent: Apache-HttpClient/4.5.5 (Java/1.8.0_231)"+LINE_SEPARATOR);
		requestHeadTextArea.appendText("Accept-Encoding: gzip,deflate"+LINE_SEPARATOR);
	}

	public void onSendRequestBtnClick(ActionEvent event){
		sendRequest();
	}

	private void sendRequest(){
		String method=methodChoiceBox.getValue();
		String url=urlTextField.getText();
		String data=requestBodyTextArea.getText();
		try(CloseableHttpClient httpclient = HttpClients.createDefault()){
			HttpRequestBase request;
            if(HttpGet.METHOD_NAME.equals(method)){
            	HttpGet getRequest = new HttpGet(url);
            	getRequest.setConfig(buildRequestConfig());
            	getRequest.setHeaders(buildRequestHeaders());
            	request = getRequest;
    		}else if(HttpPost.METHOD_NAME.equals(method)){
    			HttpPost postRequest = new HttpPost(url);
    			postRequest.setConfig(buildRequestConfig());
    			postRequest.setHeaders(buildRequestHeaders());

    			Header requestContentType=postRequest.getFirstHeader("Content-Type");
    			StringEntity content;
    			if(requestContentType!=null
    					&&!requestContentType.getValue().contains("multipart/form-data")){
    				content = new StringEntity(data,requestContentType.getValue());
    			}else{
    				content = new StringEntity(data,defaultRequestEncodingTextField.getText());
    			}
    			postRequest.setEntity(content);

    			request = postRequest;
    		}else{
    			throw new UnsupportedOperationException("不支持的请求方法！");
    		}
            appLogger.info(request.getRequestLine());
            try(CloseableHttpResponse response = httpclient.execute(request)){
            	appLogger.info(response.getStatusLine());
                //读取响应体
            	HttpEntity entify = response.getEntity();
                String resStr;
                Header responseContentType=entify.getContentEncoding();
                if(responseContentType!=null){
                	resStr=EntityUtils.toString(entify);
                }else{
                	resStr=EntityUtils.toString(entify,defaultResponseEncodingTextField.getText());
                }
                responseBodyTextArea.setText(resStr);

                //读取响应头
                StringBuilder headerBuilder=new StringBuilder();
                Header[] headers = response.getAllHeaders();
                for(Header header:headers){
                	headerBuilder.append(header.getName()).append(": ").append(header.getValue()).append(LINE_SEPARATOR);
                }
                responseHeadTextArea.setText(headerBuilder.toString());
            }
        } catch (IOException e) {
            AlertUtil.exception(e);
        }
	}

	private RequestConfig buildRequestConfig() {
		int connectTimeout = Integer.parseInt(connectTimeoutTextField.getText());
		int connectionRequestTimeout = Integer.parseInt(connectionRequestTimeoutTextField.getText());
		int socketTimeout = Integer.parseInt(socketTimeoutTextField.getText());
		boolean redirectsEnabled = Boolean.parseBoolean(redirectsEnabledTextField.getText());
		boolean relativeRedirectsAllowed = Boolean.parseBoolean(relativeRedirectsAllowedTextField.getText());
		boolean circularRedirectsAllowed = Boolean.parseBoolean(circularRedirectsAllowedTextField.getText());
		int maxRedirects = Integer.parseInt(maxRedirectsTextField.getText());
		return RequestConfig.custom()
				.setConnectTimeout(connectTimeout)
				.setConnectionRequestTimeout(connectionRequestTimeout)
				.setSocketTimeout(socketTimeout)
				.setRedirectsEnabled(redirectsEnabled)
				.setRelativeRedirectsAllowed(relativeRedirectsAllowed)
				.setCircularRedirectsAllowed(circularRedirectsAllowed)
				.setMaxRedirects(maxRedirects)
				.build();
	}

	private Header[] buildRequestHeaders() {
		List<Header> headerList=new ArrayList<>();
		String requestHeaderText = requestHeadTextArea.getText();
		if(StringUtils.isNotBlank(requestHeaderText)){
			String[] headerPairs = requestHeaderText.split(LINE_SEPARATOR);
			for(String headerPair:headerPairs){
				String[] headerInfo = headerPair.split(":");
				String name = headerInfo.length>0?headerInfo[0]:null;
				String value = headerInfo.length>1?headerInfo[1]:null;
				if(StringUtils.isBlank(name)){
					continue;
				}
				headerList.add(new BasicHeader(name, value));
			}
		}
		return headerList.toArray(new Header[0]);
	}
}
